/*
 * ECARX Technology Limited is the owner of the copyright and the trade secret of this software.
 * Without permission, no one has the right to obtain, disclose or use this software in any way.
 */
package com.ecarx.systemui.plugin.ui.navigationbar

import android.car.VehicleAreaSeat
import android.car.VehicleUnit
import android.car.hardware.CarPropertyValue
import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.Display
import android.view.MotionEvent
import android.view.SoundEffectConstants
import androidx.annotation.UiThread
import com.ecarx.systemui.plugin.R
import com.ecarx.systemui.plugin.controller.hvac.HvacTempController
import com.ecarx.systemui.plugin.ui.custom.SystemBarButton
import com.ecarx.systemui.plugin.ui.dialog.base.DialogManager
import com.ecarx.systemui.plugin.utils.BitmapUtils
import com.ecarx.systemui.plugin.utils.LogUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import kotlin.math.abs

class HvacTempView : SystemBarButton {

    private val isDebug = true
    private var temp: Float = 22.0f
    private var tempInt: String = "22"
    private var tempDec: String = ".0"
    private var tempUnit = VehicleUnit.CELSIUS
    private var tempLO = false
    private var tempHI = false
    private val tempLOStr = "Lo"
    private val tempHIStr = "Hi"
    private val tempController: HvacTempController = HvacTempController.getInstance()
    private var mArea = VehicleAreaSeat.SEAT_ROW_1_LEFT
    private var isCsd = true;
    private var paint: Paint = Paint().apply {
        color = Color.WHITE
    }

    private var downBitmap: Bitmap
    private var upBitmap: Bitmap
    private var downRect = Rect(0, 0, 80, 85)
    private var upRect = Rect(262, 0, 342, 85)

    private var upTime: Long = 0
    private var rawX = 0f
    private var actionDownTemp = 0f
    private var isUserTouchMoveEvent = false
    private var isClickTempDownEvent = true
    private var isClickTempUpEvent = false
    private var mStartEventX = 0f
    private val TEMP_STEP_SIZE = 10f // 温度调节步长
    private var mTempAdjustStep = 0.5f
    private var mLastMoveX: Float = 0f

    constructor(context: Context?) : this(context!!, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context!!, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context!!,
        attrs,
        defStyleAttr
    ) {

        downBitmap = BitmapUtils.decodeRes(context, R.drawable.ic_nav_hvac_temp_down)
        upBitmap = BitmapUtils.decodeRes(context, R.drawable.ic_nav_hvac_temp_up)

        refreshTemp()
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        isCsd = display.displayId == Display.DEFAULT_DISPLAY
        mArea = if (isCsd) VehicleAreaSeat.SEAT_ROW_1_LEFT else VehicleAreaSeat.SEAT_ROW_1_RIGHT
        LogUtils.d(
            TAG,
            "onAttachedToWindow display:" + display.displayId + " isCsd:$isCsd" + " area:$mArea"
        )

        CoroutineScope(Dispatchers.IO).launch {
            tempController.registerTempCallback(tempListener)
            tempController.registerTempUnitCallback(tempUnitListener)
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()

        CoroutineScope(Dispatchers.IO).launch {
            tempController.unRegisterTempCallback(tempListener)
            tempController.unRegisterTempUnitCallback(tempUnitListener)
        }
    }

    @UiThread
    private fun showDialog() {
        val location = intArrayOf(0, 0)
        getLocationOnScreen(location)
        DialogManager.getDialogManager().showTempDialog(location, context, isCsd)
    }

    private fun refreshTemp() {
        LogUtils.d(TAG, "start refreshTemp temp : $temp")
        CoroutineScope(Dispatchers.IO).launch {
            tempUnit = tempController.getTempUnit()
            mTempAdjustStep = if (tempUnit == VehicleUnit.CELSIUS) 0.5f else 1.0f
            temp = tempController.getCurrentTemp(mArea)
            LogUtils.d(
                TAG,
                "refreshTemp temp : $temp mTempAdjustStep: $mTempAdjustStep  tempUnit:$tempUnit"
            )
            convertTemp()
            withContext(Dispatchers.Main) {
                invalidate()
            }
        }
    }


    private val tempListener = object : CarPropertyEventCallback {
        override fun onChangeEvent(value: CarPropertyValue<*>?) {
            LogUtils.d(TAG, "tempListener onChangeEvent: $value")
            refreshTemp()
        }

        override fun onErrorEvent(p0: Int, p1: Int) {

        }
    }

    private val tempUnitListener = object : CarPropertyEventCallback {
        override fun onChangeEvent(value: CarPropertyValue<*>?) {
            LogUtils.d(TAG, "tempUnitListener onChangeEvent: $value")
            refreshTemp()
        }

        override fun onErrorEvent(p0: Int, p1: Int) {

        }
    }

    override fun getContentDescriptionString(): String {
        return "HvacTempView"
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        //todo
        setMeasuredDimension(342, 80)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        canvas?.drawBitmap(downBitmap, null, downRect, paint)

        if (tempHI) {
            canvas?.drawText(tempHIStr, 140f, 70f, paint.apply {
                textSize = 70f
                style = Paint.Style.FILL
            })
        } else if (tempLO) {
            canvas?.drawText(tempLOStr, 140f, 70f, paint.apply {
                textSize = 70f
                style = Paint.Style.FILL
            })
        } else {
            canvas?.drawText(tempInt, 100f, 70f, paint.apply {
                textSize = 80f
                style = Paint.Style.FILL
            })

            canvas?.drawText(tempDec, 192f, 70f, paint.apply {
                textSize = 50f
                style = Paint.Style.FILL
            })
        }

        canvas?.drawBitmap(upBitmap, null, upRect, paint)
    }

    private fun convertTemp() {
        if (isTempLo()) {
            tempLO = true
            tempHI = false
            return
        }

        if (isTempHi()) {
            tempLO = false
            tempHI = true
            return
        }

        tempLO = false
        tempHI = false

        tempInt = temp.toInt().toString()
        val decimalFormat = DecimalFormat(".0")
        tempDec = decimalFormat.format(temp - temp.toInt())
    }

    private fun isTempLo(): Boolean {
        return (tempUnit == VehicleUnit.CELSIUS && temp <= HvacTempController.MIN_TEMP_C) ||
                (tempUnit == VehicleUnit.FAHRENHEIT && temp <= HvacTempController.MIN_TEMP_F)
    }

    private fun isTempHi(): Boolean {
        return (tempUnit == VehicleUnit.CELSIUS && temp >= HvacTempController.MAX_TEMP_C) ||
                (tempUnit == VehicleUnit.FAHRENHEIT && temp >= HvacTempController.MAX_TEMP_F)
    }

    override fun performClick(): Boolean {
        return super.performClick()
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {

        //此处解决事件异常下发 导致按钮功能异常 up后 吃掉100毫秒内持续的事件
        if (event.eventTime - upTime < 100) {
            upTime = event.eventTime
            return true
        }
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                LogUtils.d(TAG, "ACTION_DOWN")
                showDialog()

                playSoundEffect(SoundEffectConstants.CLICK)
                mStartEventX = event.x
                rawX = event.rawX
                isUserTouchMoveEvent = false

                mLastMoveX = event.x

                isClickTempDownEvent = downRect.contains(event.x.toInt(), event.y.toInt())
                isClickTempUpEvent = upRect.contains(event.x.toInt(), event.y.toInt())
            }
            MotionEvent.ACTION_MOVE -> {
                LogUtils.d(TAG, "ACTION_MOVE")
                val moveX = event.x

                if (isClickTempDownEvent) {
                    isClickTempDownEvent = downRect.contains(event.x.toInt(), event.y.toInt())
                }
                if (isClickTempUpEvent) {
                    isClickTempUpEvent = upRect.contains(event.x.toInt(), event.y.toInt())
                }

                val absMoveX: Float = abs(moveX - mStartEventX)
                if (absMoveX > 20 || isUserTouchMoveEvent) {
                    if (!isUserTouchMoveEvent) {
                        isUserTouchMoveEvent = true
                        LogUtils.d(TAG, "判断用户开始执行移动")
                    }

                    val dis = moveX - mLastMoveX
                    LogUtils.d(TAG, "move dis:$dis  moveX:$moveX  lastMoveX:$mLastMoveX ")
                    if (abs(dis) > TEMP_STEP_SIZE) {
                        mLastMoveX = moveX
                        moveDownUpTemp(dis < 0)
                    }
                }
            }
            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
                LogUtils.d(TAG, "ACTION_UP or ACTION_CANCEL")
                performClick()

                if (isClickTempDownEvent) {
                    isClickTempDownEvent = downRect.contains(event.x.toInt(), event.y.toInt())
                    clickDownUpTemp()
                }
                if (isClickTempUpEvent) {
                    isClickTempUpEvent = upRect.contains(event.x.toInt(), event.y.toInt())
                    clickDownUpTemp()
                }

                actionDownTemp = 0f
                isUserTouchMoveEvent = false
                upTime = event.eventTime

            }
        }
        return true
    }

    private fun clickDownUpTemp() {
        var currentTemp = temp
        if (isTempLo() && isClickTempDownEvent) {
            LogUtils.d(TAG, " clickDownUpTemp down but now is temp LO")
            return
        }
        if (isTempHi() && !isClickTempDownEvent) {
            LogUtils.d(TAG, " clickDownUpTemp up but now is temp HI")
            return
        }
        if (isClickTempDownEvent) {
            currentTemp -= mTempAdjustStep
        } else if (isClickTempUpEvent) {
            currentTemp += mTempAdjustStep
        }
        setTemp(currentTemp, "clickDownUpTemp")
    }

    private fun moveDownUpTemp(moveDown: Boolean) {
        if (isTempLo() && moveDown) {
            LogUtils.d(TAG, " moveDownUpTemp down but now is temp LO")
            return
        }
        if (isTempHi() && !moveDown) {
            LogUtils.d(TAG, " moveDownUpTemp up but now is temp HI")
            return
        }

        var currentTemp = temp
        if (moveDown) {
            currentTemp -= mTempAdjustStep
        } else {
            currentTemp += mTempAdjustStep
        }
        setTemp(currentTemp, "moveDownUpTemp moveDown:$moveDown")
    }

    private fun setTemp(temp: Float, reason: String) {
        LogUtils.d(TAG, "setTemp:$temp , for $reason")
        CoroutineScope(Dispatchers.IO).launch {
            tempController.setTemp(temp, mArea)
        }
    }

    companion object {
        private const val TAG = "HvacTempView"
    }
}